<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>受试者管理 - {{trial.trial_name}}</title>
    <link href="/apps/css/bootstrap.min.css" rel="stylesheet">
    <link href="/apps/css/fontawesome-free-6.4.0-web/css/all.css" rel="stylesheet">
    <script src="/apps/js/bootstrap.bundle.min.js"></script>
    <script src="/apps/js/baidu-tongji-mtx.js"></script>
</head>
<body>
    <div class="container py-4">
        <div class="row mb-4">
            <div class="col">
                <h2>
                    <a href="/apps/trial" class="text-decoration-none">临床研究支持</a>
                    <i class="bi bi-chevron-right"></i>
                    <a href="/apps/trial/admin/trials" class="text-decoration-none">试验管理</a>
                    <i class="bi bi-chevron-right"></i>
                    {{trial.trial_code}} - 受试者管理
                </h2>
            </div>
        </div>

        <!-- 在标签页上方添加搜索框 -->
        <div class="card mb-3">
            <div class="card-body">
                <div class="row g-2">
                    <div class="col-md-8">
                        <div class="input-group">
                            <input type="text" class="form-control" id="searchInput" placeholder="搜索受试者姓名/电话/联系人...">
                            <button class="btn btn-outline-primary" type="button" id="searchButton">
                                <i class="fas fa-search"></i> 搜索
                            </button>
                            <button class="btn btn-outline-secondary" type="button" id="clearSearchButton">
                                <i class="fas fa-times"></i> 清除
                            </button>
                        </div>
                        <div class="form-text">支持搜索受试者姓名、电话号码或联系人姓名</div>
                    </div>
                    <div class="col-md-4 text-end">
                        <a href="/apps/trial/admin/trials/{{trial.id}}/dashboard" class="btn btn-primary">
                            <i class="fas fa-chart-line"></i> 试验看板
                        </a>
                    </div>
                </div>
            </div>
        </div>

        <ul class="nav nav-tabs" id="subjectTabs" role="tablist">
            <li class="nav-item" role="presentation">
                <button class="nav-link active" id="status-3-tab" data-bs-toggle="tab" data-bs-target="#status-3" type="button" role="tab" aria-controls="status-3" aria-selected="false">已在组 <span class="badge bg-success">{{lookup groupCounts "3"}}</span></button>
            </li>
            <li class="nav-item" role="presentation">
                <button class="nav-link" id="status-2-tab" data-bs-toggle="tab" data-bs-target="#status-2" type="button" role="tab" aria-controls="status-2" aria-selected="false">已入组 <span class="badge bg-danger">{{lookup groupCounts "2"}}</span></button>
            </li>
            <li class="nav-item" role="presentation">
                <button class="nav-link" id="status-1-tab" data-bs-toggle="tab" data-bs-target="#status-1" type="button" role="tab" aria-controls="status-1" aria-selected="false">已报名 <span class="badge bg-warning">{{lookup groupCounts "1"}}</span></button>
            </li>
            <li class="nav-item" role="presentation">
                <button class="nav-link" id="status-4-tab" data-bs-toggle="tab" data-bs-target="#status-4" type="button" role="tab" aria-controls="status-4" aria-selected="false">已退组 <span class="badge bg-secondary">{{lookup groupCounts "4"}}</span></button>
            </li>
            <li class="nav-item" role="presentation">
                <button class="nav-link" id="status-5-tab" data-bs-toggle="tab" data-bs-target="#status-5" type="button" role="tab" aria-controls="status-5" aria-selected="false">取消报名 <span class="badge bg-secondary">{{lookup groupCounts "5"}}</span></button>
            </li>
            <li class="nav-item" role="presentation">
                <button class="nav-link" id="status-6-tab" data-bs-toggle="tab" data-bs-target="#status-6" type="button" role="tab" aria-controls="status-6" aria-selected="false">取消入组 <span class="badge bg-secondary">{{lookup groupCounts "6"}}</span></button>
            </li>
            <li class="nav-item" role="presentation">
                <button class="nav-link" id="status-9-tab" data-bs-toggle="tab" data-bs-target="#status-9" type="button" role="tab" aria-controls="status-9" aria-selected="false">已完成 <span class="badge bg-secondary">{{lookup groupCounts "9"}}</span></button>
            </li>
            <li class="nav-item" role="presentation">
                <button class="nav-link" id="status-0-tab" data-bs-toggle="tab" data-bs-target="#status-0" type="button" role="tab" aria-controls="status-0" aria-selected="true">未报名 <span class="badge bg-secondary">{{lookup groupCounts "0"}}</span></button>
            </li>
            <li class="nav-item" role="presentation" id="search-results-tab-container" style="display: none;">
                <button class="nav-link" id="search-results-tab" data-bs-toggle="tab" data-bs-target="#search-results" type="button" role="tab" aria-controls="search-results" aria-selected="false">
                    搜索结果 <span class="badge bg-primary" id="search-count">0</span>
                </button>
            </li>
        </ul>
        <div class="tab-content" id="subjectTabsContent">
            {{#each (groupByStatus subjects) as |group|}}
            <div class="tab-pane fade {{#if (eq group.status 3)}}show active{{/if}}" id="status-{{group.status}}" role="tabpanel" aria-labelledby="status-{{group.status}}-tab">
                <div class="row row-cols-1 row-cols-md-2 g-4 mt-3">
                    {{#each group.subjects as |subject|}}
                    <div class="col-md-6 col-lg-4 mb-3">
                        <div class="card h-100 {{#if (eq subject.status 4)}}bg-light{{/if}}" data-subject-id="{{subject.id}}" data-user-id="{{subject.user_id}}">
                            <div class="card-header d-flex justify-content-between align-items-center">
                                <h5>
                                    <span class="badge {{#if (eq subject.group_type 1)}}bg-success{{else if (eq subject.group_type 2)}}bg-danger{{else}}bg-secondary{{/if}}">
                                        {{subject.group_type_text}}
                                    </span>
                                    {{subject.group_no}}
                                    <small class="text-muted">({{subject.user_id}}-{{subject.id}} {{subject.real_name}} {{subject.phone}})</small>
                                </h5>
                            </div>
                            <div class="card-body">
                                <p class="card-text">
                                    {{#if (eq subject.status 0)}}
                                    {{/if}}
                                    {{#if (eq subject.status 1)}}
                                        {{#with (parseJson subject.apply_info)}}
                                            报名信息：{{formatGender gender}} {{calculateAge birth_date}}岁<br>
                                            联系信息：{{maskNa contact_name}} {{maskNa contact_phone}} {{maskNa contact_address}}<br>
                                            计划面诊：{{planned_visit_date}}
                                        {{/with}}
                                    {{/if}}
                                    {{#if (eq subject.status 2)}}
                                        受试人：{{#with (parseJson subject.entry_info)}} {{name}} {{gender}} {{age}}岁{{/with}}<br>
                                        联系人：{{#with (parseJson subject.entry_info)}} {{maskNa recipient_name}} {{guardian_name}} {{maskNa recipient_phone}} {{maskNa guardian_phone}} {{/with}}<br>
                                        地　址：{{#with (parseJson subject.entry_info)}} {{maskNa recipient_address}} {{guardian_address}} {{/with}}
                                    {{/if}}
                                    {{#if (eq subject.status 3)}}
                                        受试人：{{#with (parseJson subject.entry_info)}} {{name}} {{gender}} {{age}}岁{{/with}}<br>
                                        联系人：{{#with (parseJson subject.entry_info)}} {{maskNa recipient_name}} {{guardian_name}} {{maskNa recipient_phone}} {{maskNa guardian_phone}} {{/with}}<br>
                                        地　址：{{#with (parseJson subject.entry_info)}} {{maskNa recipient_address}} {{guardian_address}} {{/with}}
                                    {{/if}}
                                    {{#if (eq subject.status 5)}}
                                        报名信息：{{formatGender gender}} {{calculateAge birth_date}}岁<br>
                                        取消记录：{{subject.exit_reason}} {{#with (parseJson subject.exit_info)}} {{operator}} {{moment}}{{/with}}<br>
                                        取消说明：{{#with (parseJson subject.exit_info)}} {{description}} {{/with}}
                                    {{/if}}
                                    {{#if (eq subject.status 6)}}
                                        受试信息：{{#with (parseJson subject.entry_info)}} {{name}} {{gender}} {{age}}岁{{/with}}<br>
                                        取消记录：{{subject.exit_reason}} {{#with (parseJson subject.exit_info)}} {{operator}} {{moment}}{{/with}}<br>
                                        取消说明：{{#with (parseJson subject.exit_info)}} {{description}} {{/with}}
                                    {{/if}}
                                    {{#if (eq subject.status 9)}}
                                        受试人：{{#with (parseJson subject.entry_info)}} {{name}} {{gender}} {{age}}岁{{/with}}<br>
                                        联系人：{{#with (parseJson subject.entry_info)}} {{maskNa recipient_name}} {{guardian_name}} {{maskNa recipient_phone}} {{maskNa guardian_phone}} {{/with}}<br>
                                        地　址：{{#with (parseJson subject.entry_info)}} {{maskNa recipient_address}} {{guardian_address}} {{/with}}<br>
                                        完成时间：{{formatDate subject.finish_time "YYYY-MM-DD HH:mm"}}<br>
                                        {{#if (lt (now) (addDays subject.finish_time 90))}}
                                        <div class="alert alert-success mt-2 mb-0 py-1">
                                            <i class="fas fa-clock me-1"></i>附加随访截止日期：{{formatDate (addDays subject.finish_time 90) "YYYY-MM-DD"}}
                                        </div>
                                        {{/if}}
                                    {{/if}}
                                </p>
                                {{#if subject.latest_profile}}
                                <div class="mt-2 p-2 bg-light border-start border-primary border-3 rounded">
                                    <small class="text-muted">
                                        <i class="fas fa-comment-dots me-1"></i>
                                        {{formatDate (multiply subject.latest_profile.add_time 1000) "YYYY-MM-DD HH:mm"}} · {{subject.latest_profile.operator_name}}
                                        {{#if subject.latest_profile.confidentiality}}
                                            {{#if (eq subject.latest_profile.confidentiality "TopSecret")}}
                                                <span class="badge bg-danger">绝密档案</span>
                                            {{else if (eq subject.latest_profile.confidentiality "Secret")}}
                                                <span class="badge bg-warning text-dark">机密档案</span>
                                            {{else if (eq subject.latest_profile.confidentiality "Confidential")}}
                                                <span class="badge bg-info text-dark">内部档案</span>
                                            {{else}}
                                                <span class="badge bg-secondary">普通档案</span>
                                            {{/if}}
                                        {{/if}}
                                    </small>
                                    <p class="mb-0">{{subject.latest_profile.content}}</p>
                                    {{#if subject.latest_profile.attachment_urls}}
                                        <div class="d-flex flex-wrap gap-1 mt-1">
                                            {{#each subject.latest_profile.attachment_urls}}
                                                {{#if (lt @index 3)}}
                                                <a href="javascript:showImageModal('{{this}}')" class="me-1">
                                                    <img src="{{this}}" alt="附件" class="rounded" style="width: 30px; height: 30px; object-fit: cover;">
                                                </a>
                                                {{/if}}
                                            {{/each}}
                                            {{#if (gt subject.latest_profile.attachment_urls.length 3)}}
                                                <span class="badge bg-secondary align-self-center">+{{subtract subject.latest_profile.attachment_urls.length 3}}</span>
                                            {{/if}}
                                        </div>
                                    {{/if}}
                                </div>
                                {{/if}}
                            </div>
                            <div class="card-footer">
                                <div class="btn-group">
                                    {{#if (eq subject.status 2)}}
                                    <button type="button" class="btn btn-sm btn-primary"
                                            data-bs-toggle="modal"
                                            data-bs-target="#groupModal"
                                            data-subject-id="{{subject.id}}"
                                            data-subject-name="{{subject.real_name}}"
                                            data-user-id="{{subject.user_id}}">
                                        <i class="fas fa-users me-1"></i>设置分组
                                    </button>
                                    <button type="button" class="btn btn-sm btn-outline-danger" onclick="showCancelModal({{subject.id}})">
                                        <i class="fas fa-times-circle me-1"></i>取消入组
                                    </button>
                                    {{/if}}
                                    {{#if (eq subject.status 1)}}
                                    <button type="button" class="btn btn-sm btn-outline-danger" onclick="showCancelModal({{subject.id}})">
                                        <i class="fas fa-times-circle me-1"></i>取消报名
                                    </button>
                                    {{/if}}
                                    {{#if (eq subject.status 3)}}
                                    <button type="button" class="btn btn-sm btn-outline-danger" onclick="showExitModal({{subject.id}})">退出试验</button>
                                    <button type="button" class="btn btn-sm btn-outline-success" onclick="showFinishModal({{subject.id}})">完成试验</button>
                                    {{/if}}
                                    <a href="/apps/trial/admin/trials/{{subject.trial_id}}/subjects/{{subject.id}}" class="btn btn-sm btn-outline-primary" target="_blank">
                                        <i class="fas fa-eye me-1"></i>查看详情
                                    </a>
                                    {{#if (eq subject.status 3)}}
                                    <a href="/apps/trial/diary/list/{{subject.trial_id}}?subject_id={{subject.id}}" class="btn btn-sm btn-outline-info" target="_blank">
                                        <i class="fas fa-book me-1"></i>受试日志
                                    </a>
                                    {{/if}}
                                    <button type="button" class="btn btn-sm btn-outline-secondary" onclick="showProfileModal({{subject.id}}, {{subject.trial_id}}, {{subject.user_id}})">
                                        <i class="fas fa-comment me-1"></i>备注档案
                                    </button>
                                </div>
                            </div>
                        </div>
                    </div>
                    {{/each}}
                </div>
            </div>
            {{/each}}
            <div class="tab-pane fade" id="search-results" role="tabpanel" aria-labelledby="search-results-tab">
                <div class="row row-cols-1 row-cols-md-2 g-4 mt-3" id="searchResultsContainer">
                    <div class="col-12">
                        <div class="alert alert-info">
                            请输入搜索关键词并点击搜索按钮
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- 批准入组模态框 -->
    <div class="modal fade" id="approveModal" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content">
                <form id="approveForm" method="POST">
                    <div class="modal-header">
                        <h5 class="modal-title">批准入组</h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                    </div>
                    <div class="modal-body">
                        <div class="mb-3">
                            <label class="form-label">分配组别</label>
                            <select class="form-select" name="group_type" required>
                                <option value="">请选择组别</option>
                                <option value="1">试验组</option>
                                <option value="2">对照组</option>
                                <option value="9">观察员</option>
                            </select>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                        <button type="submit" class="btn btn-success">确认批准</button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <!-- 退出试验模态框 -->
    <div class="modal fade" id="exitModal" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content">
                <form id="exitForm" method="POST">
                    <div class="modal-header">
                        <h5 class="modal-title">退出试验</h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                    </div>
                    <div class="modal-body">
                        <div class="mb-3">
                            <label class="form-label">退出原因</label>
                            <select class="form-select" name="exit_reason" required>
                                <option value="">请选择退出原因</option>
                                <option value="adverse_event">出现不良反应</option>
                                <option value="personal">个人原因</option>
                                <option value="protocol_violation">违反试验方案</option>
                                <option value="lost_followup">失访</option>
                                <option value="other">其他原因</option>
                            </select>
                        </div>
                        <div class="mb-3">
                            <label class="form-label">详细说明</label>
                            <textarea class="form-control" name="exit_description" rows="3" required></textarea>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                        <button type="submit" class="btn btn-danger">确认退出</button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <!-- 完成试验模态框 -->
    <div class="modal fade" id="finishModal" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content">
                <form id="finishForm" method="POST">
                    <div class="modal-header">
                        <h5 class="modal-title">完成试验</h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                    </div>
                    <div class="modal-body">
                        <div class="mb-3">
                            <label class="form-label">完成总结</label>
                            <textarea class="form-control" name="finish_summary" rows="3" required></textarea>
                        </div>
                        <div class="mb-3">
                            <label class="form-label">效果评价</label>
                            <select class="form-select" name="effectiveness" required>
                                <option value="">请选择效果评价</option>
                                <option value="excellent">显著改善</option>
                                <option value="good">有所改善</option>
                                <option value="fair">略有改善</option>
                                <option value="poor">无明显改善</option>
                                <option value="tbd">尚无结论</option>
                            </select>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                        <button type="submit" class="btn btn-success">确认完成</button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <!-- 受试者详情模态框 -->
    <div class="modal fade" id="subjectInfoModal" tabindex="-1">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">受试者详情</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <div id="subjectInfoContent"></div>
                </div>
            </div>
        </div>
    </div>

    <!-- 分组对话框 -->
    <div class="modal fade" id="groupModal" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">设置分组 <span id="subject-id-display"></span></h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <form id="groupForm">
                        <input type="hidden" id="subject-id" name="subjectId">
                        <input type="hidden" id="subject-user-id" name="subjectUserId">
                        <div class="mb-3">
                            <label class="form-label">分组类型</label>
                            <select class="form-select" name="groupType" id="group-type" onchange="updateGroupInfo(this.value)">
                                <option value="0">未分组</option>
                                <!-- 分组选项将在这里动态生成 -->
                            </select>
                        </div>
                        <!-- 分组信息显示区域 -->
                        <div id="group-info-container" class="mb-3">
                            <!-- 分组信息将在这里动态显示 -->
                        </div>
                        <div class="mb-3">
                            <label class="form-label">入组编号</label>
                            <input type="text" class="form-control" id="group-no" name="groupNo">
                        </div>
                        <div class="mb-3">
                            <label class="form-label">备注</label>
                            <textarea class="form-control" id="group-note" name="groupNote" rows="3"></textarea>
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                    <button type="button" class="btn btn-primary" onclick="submitGroup()">保存</button>
                </div>
            </div>
        </div>
    </div>

    <!-- 取消报名模态框 -->
    <div class="modal fade" id="cancelModal" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content">
                <form id="cancelForm" method="POST">
                    <div class="modal-header">
                        <h5 class="modal-title">取消报名</h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                    </div>
                    <div class="modal-body">
                        <div class="mb-3">
                            <label class="form-label">取消原因</label>
                            <select class="form-select" name="exit_reason" required>
                                <option value="">请选择取消原因</option>
                                <option value="admin_cancel">管理员取消</option>
                                <option value="personal">个人原因</option>
                                <option value="not_suitable">不符合试验条件</option>
                                <option value="duplicate">重复报名</option>
                                <option value="other">其他原因</option>
                            </select>
                        </div>
                        <div class="mb-3">
                            <label class="form-label">详细说明</label>
                            <textarea class="form-control" name="exit_description" rows="3" required></textarea>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                        <button type="submit" class="btn btn-danger">确认取消</button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <!-- 备注档案模态框 -->
    <div class="modal fade" id="profileModal" tabindex="-1">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">备注档案</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <form id="profileForm" enctype="multipart/form-data">
                        <input type="hidden" name="subjectId" id="profile-subject-id">
                        <input type="hidden" name="trialId" id="profile-trial-id">
                        <input type="hidden" name="userId" id="profile-user-id">
                        <input type="hidden" name="attachmentUrls" id="profile-attachment-urls">

                        <div class="mb-3">
                            <label class="form-label">备注内容</label>
                            <textarea class="form-control" name="content" rows="4" required></textarea>
                        </div>
                        <div class="mb-3">
                            <label class="form-label">保密级别</label>
                            <select class="form-select" name="secretLevel">
                                <option value="Unclassified">普通档案</option>
                                <option value="Confidential" selected>内部档案（默认）</option>
                                <option value="Secret">机密档案</option>
                                <option value="TopSecret">绝密档案</option>
                            </select>
                        </div>
                        <div class="mb-3">
                            <label class="form-label">附件截图</label>
                            <div class="input-group mb-3">
                                <input type="file" class="form-control" id="profile-file-upload" accept="image/*" multiple>
                                <button class="btn btn-outline-secondary" type="button" id="upload-btn">上传</button>
                            </div>
                            <div class="form-text">支持多个JPG、PNG格式的图片</div>
                            <div id="upload-preview" class="mt-2 d-flex flex-wrap gap-2"></div>
                        </div>
                    </form>

                    <div id="profile-history" class="mt-4">
                        <h6>历史备注</h6>
                        <div id="profile-history-content">
                            <!-- 历史备注将在这里显示 -->
                            <div class="d-flex justify-content-center">
                                <div class="spinner-border text-primary" role="status">
                                    <span class="visually-hidden">加载中...</span>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
                    <button type="button" class="btn btn-primary" onclick="submitProfile()">保存备注</button>
                </div>
            </div>
        </div>
    </div>

    <!-- 将所有JS文件移到这里，并添加defer属性 -->
    <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js" defer></script>
    <script src="/apps/js/wx-client-dom.js" defer></script>
    <script src="/apps/js/open-oss-img-in-modal.js" defer></script>

    <script>
        const approveModal = new bootstrap.Modal(document.getElementById('approveModal'));
        const exitModal = new bootstrap.Modal(document.getElementById('exitModal'));
        const finishModal = new bootstrap.Modal(document.getElementById('finishModal'));
        const subjectInfoModal = new bootstrap.Modal(document.getElementById('subjectInfoModal'));
        const cancelModal = new bootstrap.Modal(document.getElementById('cancelModal'));
        const profileModal = new bootstrap.Modal(document.getElementById('profileModal'));

        function showApproveModal(subjectId) {
            const form = document.getElementById('approveForm');
            form.action = `/apps/trial/admin/trials/subjects/${subjectId}/approve`;
            approveModal.show();
        }

        function showExitModal(subjectId) {
            const form = document.getElementById('exitForm');
            form.action = `/apps/trial/subjects/${subjectId}/exit`;
            exitModal.show();
        }

        function showFinishModal(subjectId) {
            const form = document.getElementById('finishForm');
            form.action = `/apps/trial/subjects/${subjectId}/finish`;
            finishModal.show();
        }

        function showCancelModal(subjectId) {
            const form = document.getElementById('cancelForm');
            form.action = `/apps/trial/subjects/${subjectId}/cancel`;
            cancelModal.show();
        }

        // 显示备注档案模态框
        function showProfileModal(subjectId, trialId, userId) {
            document.getElementById('profile-subject-id').value = subjectId;
            document.getElementById('profile-trial-id').value = trialId;
            document.getElementById('profile-user-id').value = userId;
            document.getElementById('profile-attachment-urls').value = '';

            // 清空表单和预览
            document.getElementById('profileForm').reset();
            document.getElementById('upload-preview').innerHTML = '';

            // 加载历史备注
            loadProfileHistory(userId, subjectId, trialId);

            profileModal.show();
        }

        // 加载历史备注
        async function loadProfileHistory(userId, subjectId, trialId) {
            try {
                const response = await fetch(`/apps/trial/subjects/${subjectId}/profiles?trial_id=${trialId}`);
                const result = await response.json();

                const historyContent = document.getElementById('profile-history-content');

                if (result.success) {
                    if (result.profiles.length === 0) {
                        historyContent.innerHTML = '<div class="alert alert-info">暂无历史备注</div>';
                        return;
                    }

                    let html = '<div class="list-group">';
                    result.profiles.forEach(profile => {
                        // 根据confidentiality字段获取对应的显示名称和样式
                        let secretLevelText = '普通档案';
                        let badgeClass = 'bg-secondary';

                        switch (profile.confidentiality) {
                            case 'TopSecret':
                                secretLevelText = '绝密档案';
                                badgeClass = 'bg-danger';
                                break;
                            case 'Secret':
                                secretLevelText = '机密档案';
                                badgeClass = 'bg-warning text-dark';
                                break;
                            case 'Confidential':
                                secretLevelText = '内部档案';
                                badgeClass = 'bg-info text-dark';
                                break;
                            case 'Unclassified':
                            default:
                                secretLevelText = '普通档案';
                                badgeClass = 'bg-secondary';
                                break;
                        }

                        let attachmentsHtml = '';
                        if (profile.attachment_urls ) {
                            attachmentsHtml = '<div class="d-flex flex-wrap gap-2 mt-2">';
                            const urls = JSON.parse(profile.attachment_urls);
                            urls.forEach( url => {
                                attachmentsHtml += `<a href="javascript:showImageModal('${url}')" class="me-2">
                                    <img src="${url}" alt="附件" class="img-thumbnail" style="width: 80px; height: 80px; object-fit: cover;">
                                </a>`;
                            });
                            attachmentsHtml += '</div>';
                        }

                        // 使用add_time字段，转换为可读的日期时间
                        const createdAt = new Date(profile.add_time * 1000).toLocaleString();

                        html += `
                        <div class="list-group-item">
                            <div class="d-flex justify-content-between align-items-center">
                                <small class="text-muted">${createdAt} · ${profile.operator_name || '系统'} · <span class="badge ${badgeClass}">${secretLevelText}</span></small>
                            </div>
                            <p class="mb-1 mt-2">${profile.content}</p>
                            ${attachmentsHtml}
                        </div>`;
                    });
                    html += '</div>';

                    historyContent.innerHTML = html;
                } else {
                    historyContent.innerHTML = `<div class="alert alert-danger">${result.message || '加载备注历史失败'}</div>`;
                }
            } catch (error) {
                console.error('加载备注历史失败:', error);
                document.getElementById('profile-history-content').innerHTML = '<div class="alert alert-danger">加载备注历史失败，请重试</div>';
            }
        }

        // 提交备注档案
        async function submitProfile() {
            const form = document.getElementById('profileForm');
            const subjectId = document.getElementById('profile-subject-id').value;
            const trialId = document.getElementById('profile-trial-id').value;
            const userId = document.getElementById('profile-user-id').value;
            const content = form.querySelector('[name="content"]').value;
            const confidentiality = form.querySelector('[name="secretLevel"]').value;
            const attachmentUrls = document.getElementById('profile-attachment-urls').value;

            if (!content) {
                alert('请填写备注内容');
                return;
            }

            try {
                const response = await fetch(`/apps/trial/subjects/${subjectId}/profile`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({
                        trialId,
                        userId,
                        content,
                        confidentiality,
                        attachmentUrls: attachmentUrls ? JSON.parse(attachmentUrls) : []
                    })
                });

                const result = await response.json();

                if (result.success) {
                    alert('备注档案保存成功');
                    loadProfileHistory(userId, subjectId, trialId);
                    form.reset();
                    document.getElementById('upload-preview').innerHTML = '';
                    document.getElementById('profile-attachment-urls').value = '';
                } else {
                    alert(result.message || '保存备注档案失败');
                }
            } catch (error) {
                console.error('保存备注档案失败:', error);
                alert('保存备注档案失败，请重试');
            }
        }

        async function viewSubjectInfo(subjectId) {
            try {
                const response = await fetch(`/apps/trial/admin/trials/subjects/${subjectId}/info`);
                const result = await response.json();

                if (result.success) {
                    const subject = result.subject;
                    const content = document.getElementById('subjectInfoContent');

                    // 根据状态显示不同的信息
                    let html = `
                        <h6>基本信息</h6>
                        <dl class="row">
                            <dt class="col-sm-3">受试者编号</dt>
                            <dd class="col-sm-9">${subject.subject_no}</dd>
                            <dt class="col-sm-3">姓名</dt>
                            <dd class="col-sm-9">${subject.nickname}</dd>
                            <dt class="col-sm-3">手机号</dt>
                            <dd class="col-sm-9">${subject.phone}</dd>
                        </dl>
                    `;

                    if (subject.apply_info) {
                        const applyInfo = JSON.parse(subject.apply_info);
                        html += `
                            <h6>报名信息</h6>
                            <dl class="row">
                                <dt class="col-sm-3">报名时间</dt>
                                <dd class="col-sm-9">${new Date(subject.apply_time).toLocaleString()}</dd>
                                <dt class="col-sm-3">联系人</dt>
                                <dd class="col-sm-9">${applyInfo.contact_name}</dd>
                                <dt class="col-sm-3">联系电话</dt>
                                <dd class="col-sm-9">${applyInfo.contact_phone}</dd>
                            </dl>
                        `;
                    }

                    if (subject.entry_info) {
                        const entryInfo = JSON.parse(subject.entry_info);
                        html += `
                            <h6>登记信息</h6>
                            <dl class="row">
                                <dt class="col-sm-3">登记时间</dt>
                                <dd class="col-sm-9">${new Date(subject.entry_time).toLocaleString()}</dd>
                                <dt class="col-sm-3">ADOS评分</dt>
                                <dd class="col-sm-9">${entryInfo.ados_score}</dd>
                                <dt class="col-sm-3">ABC评分</dt>
                                <dd class="col-sm-9">${entryInfo.abc_score}</dd>
                            </dl>
                        `;
                    }

                    if (subject.exit_info) {
                        const exitInfo = JSON.parse(subject.exit_info);
                        html += `
                            <h6>退出信息</h6>
                            <dl class="row">
                                <dt class="col-sm-3">退出时间</dt>
                                <dd class="col-sm-9">${new Date(subject.exit_time).toLocaleString()}</dd>
                                <dt class="col-sm-3">退出原因</dt>
                                <dd class="col-sm-9">${exitInfo.reason}</dd>
                                <dt class="col-sm-3">详细说明</dt>
                                <dd class="col-sm-9">${exitInfo.description}</dd>
                            </dl>
                        `;
                    }

                    if (subject.finish_info) {
                        const finishInfo = JSON.parse(subject.finish_info);
                        html += `
                            <h6>完成信息</h6>
                            <dl class="row">
                                <dt class="col-sm-3">完成时间</dt>
                                <dd class="col-sm-9">${new Date(subject.finish_time).toLocaleString()}</dd>
                                <dt class="col-sm-3">效果评价</dt>
                                <dd class="col-sm-9">${finishInfo.effectiveness}</dd>
                                <dt class="col-sm-3">完成总结</dt>
                                <dd class="col-sm-9">${finishInfo.summary}</dd>
                            </dl>
                        `;
                    }

                    content.innerHTML = html;
                    subjectInfoModal.show();
                } else {
                    alert(result.message || '获取受试者信息失败');
                }
            } catch (error) {
                console.error('获取受试者信息失败:', error);
                alert('获取受试者信息失败，请重试');
            }
        }

        // 处理批准入组表单提交
        document.getElementById('approveForm').addEventListener('submit', async function(e) {
            e.preventDefault();

            const formData = new FormData(this);

            try {
                const response = await fetch(this.action, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({
                        group_type: formData.get('group_type')
                    })
                });

                const result = await response.json();
                if (result.success) {
                    window.location.reload();
                } else {
                    alert(result.message || '批准入组失败');
                }
            } catch (error) {
                console.error('批准入组失败:', error);
                alert('批准入组失败，请重试');
            }
        });

        // 处理退出表单提交
        document.getElementById('exitForm').addEventListener('submit', async function(e) {
            e.preventDefault();

            const formData = new FormData(this);
            const exitInfo = {
                reason: formData.get('exit_reason'),
                description: formData.get('exit_description')
            };

            try {
                const response = await fetch(this.action, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(exitInfo)
                });

                const result = await response.json();
                if (result.success) {
                    window.location.reload();
                } else {
                    alert(result.message || '退出失败');
                }
            } catch (error) {
                console.error('退出失败:', error);
                alert('退出失败，请重试');
            }
        });

        // 处理完成表单提交
        document.getElementById('finishForm').addEventListener('submit', async function(e) {
            e.preventDefault();

            const formData = new FormData(this);
            const finishInfo = {
                summary: formData.get('finish_summary'),
                effectiveness: formData.get('effectiveness')
            };

            try {
                const response = await fetch(this.action, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(finishInfo)
                });

                const result = await response.json();
                if (result.success) {
                    window.location.reload();
                } else {
                    alert(result.message || '完成失败');
                }
            } catch (error) {
                console.error('完成失败:', error);
                alert('完成失败，请重试');
            }
        });

        // 处理取消报名表单提交
        document.getElementById('cancelForm').addEventListener('submit', async function(e) {
            e.preventDefault();

            const formData = new FormData(this);
            const exitInfo = {
                reason: formData.get('exit_reason'),
                description: formData.get('exit_description')
            };

            try {
                const response = await fetch(this.action, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(exitInfo)
                });

                const result = await response.json();
                if (result.success) {
                    window.location.reload();
                } else {
                    alert(result.message || '取消报名失败');
                }
            } catch (error) {
                console.error('取消报名失败:', error);
                alert('取消报名失败，请重试');
            }
        });

        // 全局变量存储试验配置
        let trialGroupConfigs = [];

        // 页面加载时获取试验配置
        document.addEventListener('DOMContentLoaded', function() {
            fetchTrialConfig();

            // 监听分组模态框打开事件
            const groupModal = document.getElementById('groupModal');
            if (groupModal) {
                groupModal.addEventListener('show.bs.modal', function(event) {
                    // 获取触发按钮
                    const button = event.relatedTarget;
                    if (button) {
                        const subjectId = button.getAttribute('data-subject-id');
                        const subjectName = button.getAttribute('data-subject-name');
                        const userId = button.getAttribute('data-user-id');
                        if (subjectId && subjectName && userId) {
                            showGroupModal(subjectId, subjectName);
                        }
                    }
                });
            }
        });

        // 获取试验配置
        async function fetchTrialConfig() {
            try {
                const response = await fetch(`/apps/trial/admin/trials/{{trial.id}}`);
                const data = await response.json();

                if (data.trial && data.trial.group_config) {
                    try {
                        trialGroupConfigs = JSON.parse(data.trial.group_config);
                    } catch (e) {
                        console.error('解析分组配置失败:', e);
                        trialGroupConfigs = [];
                    }
                }
            } catch (error) {
                console.error('获取试验信息失败:', error);
            }
        }

        // 打开分组模态框
        function showGroupModal(subjectId, subjectName) {
            // 获取触发按钮并从中获取用户ID
            const button = document.querySelector(`button[data-subject-id="${subjectId}"]`);
            const userId = button ? button.getAttribute('data-user-id') : '';

            document.getElementById('subject-id').value = subjectId;
            document.getElementById('subject-user-id').value = userId;
            document.getElementById('subject-id-display').textContent = `(${userId}-${subjectId})`;

            // 清除表单
            document.getElementById('groupForm').reset();

            // 更新分组选项
            updateGroupOptions();
        }

        // 更新分组选项
        function updateGroupOptions() {
            const groupTypeSelect = document.getElementById('group-type');

            // 清除除了"未分组"选项外的所有选项
            while (groupTypeSelect.options.length > 1) {
                groupTypeSelect.remove(1);
            }

            // 根据分组配置添加选项
            if (trialGroupConfigs && trialGroupConfigs.length > 0) {
                trialGroupConfigs.forEach(config => {
                    const option = document.createElement('option');
                    option.value = config.group_type;
                    option.textContent = config.group_name;
                    groupTypeSelect.appendChild(option);
                });
            } else {
                // 如果没有配置，添加默认选项
                const options = [
                    { value: 1, text: '试验组' },
                    { value: 2, text: '对照组' },
                    { value: 9, text: '观察组' }
                ];

                options.forEach(opt => {
                    const option = document.createElement('option');
                    option.value = opt.value;
                    option.textContent = opt.text;
                    groupTypeSelect.appendChild(option);
                });
            }
        }

        // 更新分组信息显示
        function updateGroupInfo(groupType) {
            // 查找所选分组的配置
            const selectedGroup = trialGroupConfigs.find(config => config.group_type == groupType);

            // 更新分组信息显示
            const groupInfoContainer = document.getElementById('group-info-container');
            if (groupInfoContainer) {
                if (selectedGroup) {
                    groupInfoContainer.innerHTML = `
                        <div class="alert alert-info">
                            <h5>${selectedGroup.group_name}</h5>
                            <p><strong>随访天数:</strong> ${selectedGroup.duration}天</p>
                            <p><strong>每日打卡:</strong> ${selectedGroup.daily_diary ? '是' : '否'}</p>
                            <p><strong>随访日期:</strong> ${selectedGroup.follow_up_dates.join(', ')}</p>
                        </div>
                    `;
                } else {
                    groupInfoContainer.innerHTML = '';
                }
            }
        }

        // 提交分组设置
        function submitGroup() {
            const form = document.getElementById('groupForm');
            const subjectId = form.subjectId.value;
            const groupType = form.groupType.value;
            const groupNo = form.groupNo.value;
            const groupNote = form.groupNote.value;

            if (!groupType || !groupNo) {
                alert('请填写完整的分组信息');
                return;
            }

            // 显示加载状态
            const submitBtn = document.querySelector('#groupModal .btn-primary');
            const originalText = submitBtn.innerHTML;
            submitBtn.disabled = true;
            submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 处理中...';

            fetch(`/apps/trial/subjects/${subjectId}/group`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                },
                body: JSON.stringify({
                    groupType,
                    groupNo,
                    groupNote
                })
            })
            .then(response => {
                // 检查响应状态
                if (!response.ok) {
                    if (response.status === 401 || response.status === 403) {
                        throw new Error('会话已过期，请重新登录');
                    }
                    throw new Error(`服务器返回错误: ${response.status}`);
                }

                // 检查内容类型
                const contentType = response.headers.get('content-type');
                if (!contentType || !contentType.includes('application/json')) {
                    throw new Error('服务器返回了非JSON格式的响应，可能需要重新登录');
                }

                return response.json();
            })
            .then(data => {
                if (data.success) {
                    location.reload();
                } else {
                    alert(data.message || '分组设置失败');
                }
            })
            .catch(error => {
                console.error('分组设置失败:', error);

                // 针对会话过期的特殊处理
                if (error.message.includes('会话已过期') || error.message.includes('非JSON格式')) {
                    alert('您的登录会话可能已过期，请刷新页面后重试');
                } else {
                    alert('设置分组失败: ' + error.message);
                }
            })
            .finally(() => {
                // 恢复按钮状态
                submitBtn.disabled = false;
                submitBtn.innerHTML = originalText;
            });
        }

        // 页面加载完成后初始化上传功能
        document.addEventListener('DOMContentLoaded', function() {
            // 初始化文件上传按钮
            const uploadBtn = document.getElementById('upload-btn');
            if (uploadBtn) {
                uploadBtn.addEventListener('click', uploadAttachments);
            }
        });

        // 上传附件
        async function uploadAttachments() {
            const fileInput = document.getElementById('profile-file-upload');
            const files = fileInput.files;
            const uploadBtn = document.getElementById('upload-btn');

            if (!files || files.length === 0) {
                alert('请选择要上传的文件');
                return;
            }

            const uploadPreview = document.getElementById('upload-preview');
            const attachmentUrlsInput = document.getElementById('profile-attachment-urls');

            // 显示上传中状态
            uploadBtn.disabled = true;
            uploadBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 上传中...';

            try {
                const uploadPromises = [];
                const uploadedUrls = [];

                // 如果已有上传文件，获取现有URL
                let existingUrls = [];
                if (attachmentUrlsInput.value) {
                    try {
                        existingUrls = JSON.parse(attachmentUrlsInput.value);
                    } catch (e) {
                        existingUrls = [];
                    }
                }

                // 上传每个文件
                for (let i = 0; i < files.length; i++) {
                    const file = files[i];
                    const formData = new FormData();
                    formData.append('file', file);

                    const uploadPromise = fetch('https://mall.totembio.cn/api/uploadMtaFile', {
                        method: 'POST',
                        body: formData
                    })
                    .then(response => response.json())
                    .then(result => {
                        if (result.data && result.data.src) {
                            uploadedUrls.push(result.data.src);

                            // 创建预览
                            const previewItem = document.createElement('div');
                            previewItem.className = 'position-relative';
                            previewItem.innerHTML = `
                                <img src="${result.data.src}" class="img-thumbnail" style="width: 100px; height: 100px; object-fit: cover;">
                                <button type="button" class="btn-close position-absolute top-0 end-0 bg-danger"
                                        style="font-size: 0.7rem;" data-url="${result.url}"></button>
                            `;

                            // 添加删除功能
                            const closeBtn = previewItem.querySelector('.btn-close');
                            closeBtn.addEventListener('click', function() {
                                const url = this.getAttribute('data-url');
                                removeAttachment(url);
                                previewItem.remove();
                            });

                            uploadPreview.appendChild(previewItem);
                            return result.data.src;
                        } else {
                            throw new Error(result.message || '上传失败');
                        }
                    });

                    uploadPromises.push(uploadPromise);
                }

                const results = await Promise.all(uploadPromises);

                // 合并新上传的URL和现有的URL
                const allUrls = [...existingUrls, ...uploadedUrls];

                // 更新隐藏字段
                attachmentUrlsInput.value = JSON.stringify(allUrls);

                // 重置文件输入
                fileInput.value = '';

            } catch (error) {
                console.error('上传文件失败:', error);
                alert('上传文件失败: ' + error.message);
            } finally {
                // 恢复上传按钮状态
                uploadBtn.disabled = false;
                uploadBtn.innerHTML = '上传';
            }
        }

        // 移除附件
        function removeAttachment(url) {
            const attachmentUrlsInput = document.getElementById('profile-attachment-urls');
            let urls = [];

            try {
                urls = JSON.parse(attachmentUrlsInput.value);
            } catch (e) {
                urls = [];
            }

            // 从URL数组中移除指定URL
            const updatedUrls = urls.filter(item => item !== url);

            // 更新隐藏字段
            attachmentUrlsInput.value = JSON.stringify(updatedUrls);
        }

        // 从URL创建预览图片
        function createPreviewsFromUrls(urls) {
            if (!urls || urls.length === 0) return;

            const uploadPreview = document.getElementById('upload-preview');
            uploadPreview.innerHTML = '';

            urls.forEach( url => {
                const previewItem = document.createElement('div');
                previewItem.className = 'position-relative';
                previewItem.innerHTML = `
                    <img src="${url}" class="img-thumbnail" style="width: 100px; height: 100px; object-fit: cover;">
                    <button type="button" class="btn-close position-absolute top-0 end-0 bg-danger"
                            style="font-size: 0.7rem;" data-url="${url}"></button>
                `;

                // 添加删除功能
                const closeBtn = previewItem.querySelector('.btn-close');
                closeBtn.addEventListener('click', function() {
                    const url = this.getAttribute('data-url');
                    removeAttachment(url);
                    previewItem.remove();
                });

                uploadPreview.appendChild(previewItem);
            });
        }

        // 定义全局变量
        let searchInput, searchButton, clearSearchButton, searchResultsContainer, searchResultsTabContainer, searchCountBadge;

        // 初始化搜索功能
        document.addEventListener('DOMContentLoaded', function() {
            // 初始化全局变量
            searchInput = document.getElementById('searchInput');
            searchButton = document.getElementById('searchButton');
            clearSearchButton = document.getElementById('clearSearchButton');
            searchResultsContainer = document.getElementById('searchResultsContainer');
            searchResultsTabContainer = document.getElementById('search-results-tab-container');
            searchCountBadge = document.getElementById('search-count');

            // 绑定搜索按钮点击事件
            searchButton.addEventListener('click', performSearch);

            // 绑定回车键触发搜索
            searchInput.addEventListener('keyup', function(event) {
                if (event.key === 'Enter') {
                    performSearch();
                }
            });

            // 绑定清除搜索按钮点击事件
            clearSearchButton.addEventListener('click', function() {
                searchInput.value = '';
                searchResultsTabContainer.style.display = 'none';
                // 切换回第一个标签页
                document.querySelector('#subjectTabs .nav-link.active').classList.remove('active');
                document.querySelector('#subjectTabs .nav-link:first-child').classList.add('active');
                document.querySelector('#subjectTabsContent .tab-pane.active').classList.remove('show', 'active');
                document.querySelector('#subjectTabsContent .tab-pane:first-child').classList.add('show', 'active');
            });
        });

        // 修复搜索功能
        function performSearch() {
            const searchTerm = searchInput.value.trim().toLowerCase();

            if (!searchTerm) {
                alert('请输入搜索关键词');
                return;
            }

            // 获取所有受试者卡片
            const allSubjectCards = document.querySelectorAll('.card[data-subject-id]');
            const matchedSubjects = [];

            // 遍历所有受试者卡片，查找匹配项
            allSubjectCards.forEach(card => {
                const cardContent = card.textContent.toLowerCase();
                const cardClone = card.cloneNode(true);

                // 检查是否包含搜索关键词
                if (cardContent.includes(searchTerm)) {
                    matchedSubjects.push(cardClone);
                }
            });

            // 更新搜索结果
            updateSearchResults(matchedSubjects, searchTerm);

            // 显示搜索结果标签页
            searchResultsTabContainer.style.display = 'block';

            // 激活搜索结果标签页
            const searchResultsTab = document.getElementById('search-results-tab');
            const tab = new bootstrap.Tab(searchResultsTab);
            tab.show();
        }

        // 更新搜索结果
        function updateSearchResults(matchedSubjects, searchTerm) {
            // 更新结果数量
            searchCountBadge.textContent = matchedSubjects.length;

            // 清空搜索结果容器
            searchResultsContainer.innerHTML = '';

            // 如果没有匹配结果
            if (matchedSubjects.length === 0) {
                searchResultsContainer.innerHTML = `
                    <div class="col-12">
                        <div class="alert alert-warning">
                            <i class="fas fa-exclamation-triangle me-2"></i>
                            未找到包含 "${searchTerm}" 的受试者
                        </div>
                    </div>
                `;
                return;
            }

            // 添加搜索结果标题
            const resultHeader = document.createElement('div');
            resultHeader.className = 'col-12 mb-3';
            resultHeader.innerHTML = `
                <div class="alert alert-success">
                    <i class="fas fa-check-circle me-2"></i>
                    找到 ${matchedSubjects.length} 个包含 "${searchTerm}" 的受试者
                </div>
            `;
            searchResultsContainer.appendChild(resultHeader);

            // 添加匹配的受试者卡片
            matchedSubjects.forEach(card => {
                const colDiv = document.createElement('div');
                colDiv.className = 'col-md-6 col-lg-4 mb-3';
                colDiv.appendChild(card);
                searchResultsContainer.appendChild(colDiv);

                // 高亮搜索关键词
                highlightSearchTerm(card, searchTerm);
            });
        }

        // 高亮搜索关键词
        function highlightSearchTerm(element, term) {
            const walker = document.createTreeWalker(
                element,
                NodeFilter.SHOW_TEXT,
                { acceptNode: node => node.nodeValue.trim() ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT }
            );

            const nodesToReplace = [];
            let currentNode;

            // 收集包含搜索词的文本节点
            while (currentNode = walker.nextNode()) {
                if (currentNode.nodeValue.toLowerCase().includes(term.toLowerCase())) {
                    nodesToReplace.push(currentNode);
                }
            }

            // 替换文本节点，添加高亮
            nodesToReplace.forEach(node => {
                const parent = node.parentNode;
                const text = node.nodeValue;
                const regex = new RegExp(`(${term})`, 'gi');
                const newHtml = text.replace(regex, '<mark class="bg-warning">$1</mark>');

                const tempElement = document.createElement('span');
                tempElement.innerHTML = newHtml;

                // 替换原始节点
                while (tempElement.firstChild) {
                    parent.insertBefore(tempElement.firstChild, node);
                }
                parent.removeChild(node);
            });
        }
    </script>
</body>
</html>
